package com.striker.nettyconn;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.ArithmeticOperators;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class server3Handler extends Middleware {
    private final Log logger = LogFactory.getLog(this.getClass());

    //用于保存所有Channel对象
    private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    private static Map<Long, Channel> uin2channel = new HashMap<>();//todo: 用户多时需要分布式

    private MongoTemplate mongoTemplate;

    public server3Handler() {
        super("server");
        // TODO Auto-generated constructor stub
        mongoTemplate = new MongoDBConfig().mongoTemplate();
    }

    @Override
    protected void processData(ChannelHandlerContext ctx, Object msg) {
        // TODO Auto-generated method stub
        Model model = (Model) msg;
        logger.info("handlerData|uin2channel size:" + uin2channel.size());

        if (model.getType() == TypeData.LOGIN) {
            if (!uin2channel.containsKey(model.getFromUin())) {//todo: handlerAdded里是不是更好? 需要, 不然登录未发消息也以为未登录
                uin2channel.put(model.getFromUin(), ctx.channel());
                System.err.println("add channel of uin: " + model.getFromUin());
                System.err.println("uin2channel size:" + uin2channel.size() + "|" + uin2channel);
            }
            //通知a的好友a在线了
            //todo:FriendService判断是好友, 然后往channel发消息
            for (Long uin : uin2channel.keySet()) {
//                if(uin.intValue() == model.getUin().intValue()){//自己
//                    continue;
//                }
                Channel peerChannel = uin2channel.get(uin);
                peerChannel.writeAndFlush(model);
            }
            return;
        }else if(model.getType() == TypeData.C2COfflineMsg){
            //查询db
            Query query = new Query();
            query.addCriteria(
                            Criteria.where("toUin").is(model.getFromUin())
            );

            List<Model> resultList = mongoTemplate.find(query, Model.class);
            //发消息到client
            for(int i = 0; i < resultList.size(); i++) {
                Model respModel = new Model();
                respModel.setType(TypeData.C2COfflineMsg);
                respModel.setToUin(model.getFromUin());
                respModel.setFromUin(model.getToUin());
                respModel.setBody("test offline");
                respModel.setType(TypeData.C2COfflineMsg);
                Channel peerChannel = uin2channel.get(model.getFromUin());
                peerChannel.writeAndFlush(respModel);
            }
        }
        logger.info("server 接收数据 ： " + model.toString());
        model.setType(TypeData.CUSTOMER);
        model.setBody(model.getBody());
        //基于uin
        Channel peerChannel = uin2channel.get(model.getToUin());
        if (null != peerChannel) {
            peerChannel.writeAndFlush(model);
            logger.info("server往channel:" + ctx.name() + "|发送数据:" + model.toString());
        } else {
            logger.info("对方不在线|入db");
            //todo:modelRepository.save(model);
            mongoTemplate.insert(model);
        }

        /*
        //channel为当前客户端: 即发msg给服务端的channel
        Channel channel = ctx.channel();
        channelGroup.forEach(ch -> {
            if(channel != ch){
                ch.writeAndFlush(model);
                logger.info("server往channel:"+ctx.name()+"|发送数据:" + model.toString());
            } else{
                logger.info("server往原来channel:"+ctx.name()+"|发送数据:" + model.toString());
                ch.writeAndFlush(msg);
            }
        });
        */
    }

    @Override
    protected void handlerReaderIdle(ChannelHandlerContext ctx) {
        // TODO Auto-generated method stub
        super.handlerReaderIdle(ctx);
        System.err.println(" ---- client " + ctx.channel().remoteAddress().toString() + " reader timeOut, --- close it");
        ctx.close();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        logger.error(name + "  exception" + cause.toString());
        cause.printStackTrace();
        ctx.close();
    }

    //表示连接时活动状态
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
//        // TODO Auto-generated method stub
        Channel channel = ctx.channel();
        //广播消息给所有的客户端
        System.err.println(channel.remoteAddress() + " 上线 \n");
    }

    //表示客户端与服务器连接建立
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //chanel可以理解成Connection
        Channel channel = ctx.channel();
        //广播消息给所有的客户端
        //channelGroup.writeAndFlush("[服务器] - " + channel.remoteAddress() + " 加入\n");
        channelGroup.add(channel);
        System.err.println(channel.remoteAddress() + " 连接建立 \n");
    }

    /* //todo 为什么不用channelRead
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        try {
            // Do something with msg
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }*/

    //表示连接断掉了
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        for (Long uin : uin2channel.keySet()) {
            if (uin2channel.get(uin) == channel) {
                //uin2channel.remove(uin);
                System.err.println("下线|uin:" + uin);
                break;
            }
        }
        //广播消息给所有的客户端
        //channelGroup.writeAndFlush("[服务器] - " + channel.remoteAddress() + " 离开\n");
        //下面这行代码Netty会自动调用
        //channelGroup.remove(channel);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        //广播消息给所有的客户端
        System.err.println(channel.remoteAddress() + " 下线 \n");
    }

    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        //channel为当前客户端: 即发msg给服务端的channel
//        Channel channel = ctx.channel();
//        channelGroup.forEach(ch -> {
//            if (channel != ch) {
//                logger.info(channel.remoteAddress() + " 发送的消息:" + msg + "\n");
//            } else {
//                logger.info("[自己]" + msg + " \n");
//            }
//        });
//        Error:(179, 33) java: -source 1.7 中不支持 lambda 表达式
//                (请使用 -source 8 或更高版本以启用 lambda 表达式)
    }
}
